package cate.game.log;

import cate.game.GameBody;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.filter.ThresholdFilter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import ch.qos.logback.core.util.FileSize;
import ch.qos.logback.core.util.OptionHelper;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class GameSrvLogger {
    private static ConsoleAppender<ILoggingEvent> consoleAppender;
    private static Map<Integer, RollingFileAppender<ILoggingEvent>> fileAppenders;
    private Logger logger;

    public GameSrvLogger(GameBody gameBody, String className){
        String nClassName = className + "_game" + gameBody.config.srvId;
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        Logger log = context.getLogger(nClassName);
        log.setAdditive(false);
        log.setLevel(Level.INFO);
        addConsoleAppender(log);
        this.logger = addFileAppender(gameBody, log);
    }

    public Logger raw() {
        return this.logger;
    }

    private synchronized void addConsoleAppender(Logger log){
        if(consoleAppender == null){
            consoleAppender = new ConsoleAppender<>();
            ThresholdFilter filter = new ThresholdFilter();
            filter.setLevel("INFO");
            filter.start();
            filter.setContext(log.getLoggerContext());
            consoleAppender.setContext(log.getLoggerContext());
            consoleAppender.addFilter(filter);
            consoleAppender.setWithJansi(true);
            PatternLayoutEncoder layoutEncoder = new PatternLayoutEncoder();
            layoutEncoder.setContext(log.getLoggerContext());
            layoutEncoder.setPattern(LogConstants.GAME_CONSOLE_PATTERN);
            layoutEncoder.setCharset(StandardCharsets.UTF_8);
            layoutEncoder.start();
            consoleAppender.setEncoder(layoutEncoder);
            consoleAppender.start();
        }
        log.addAppender(consoleAppender);
    }

    private synchronized Logger addFileAppender(GameBody gameBody, Logger log){
        if(fileAppenders == null){
            fileAppenders = new HashMap<>();
        }
        if(!fileAppenders.containsKey(gameBody.config.srvId)){
            PatternLayoutEncoder layoutEncoder = new PatternLayoutEncoder();
            layoutEncoder.setContext(log.getLoggerContext());
            layoutEncoder.setPattern(LogConstants.GAME_LOG_INFO_PATTERN);
            layoutEncoder.setCharset(StandardCharsets.UTF_8);
            layoutEncoder.start();
            RollingFileAppender<ILoggingEvent> rfa = new RollingFileAppender<>();
            rfa.setFile(OptionHelper.substVars(
                    ".logs/game-"+gameBody.config.srvId+"-info.log", log.getLoggerContext()));
            rfa.setContext(log.getLoggerContext());
            rfa.setEncoder(layoutEncoder);
            rfa.setAppend(true);
            TimeBasedRollingPolicy<ILoggingEvent> filePolicy =
                    new TimeBasedRollingPolicy<>();
            filePolicy.setContext(log.getLoggerContext());
            filePolicy.setParent(rfa);
            SizeAndTimeBasedFNATP<ILoggingEvent> triggerPolicy = new SizeAndTimeBasedFNATP<>();
            triggerPolicy.setContext(log.getLoggerContext());
            triggerPolicy.setMaxFileSize(FileSize.valueOf(LogConstants.GAME_LOG_MAX_FILE));
            filePolicy.setTimeBasedFileNamingAndTriggeringPolicy(triggerPolicy);
            filePolicy.setFileNamePattern(
                    OptionHelper.substVars(
                            ".logs/info/cate-game-"+gameBody.config.srvId+"/" + gameBody.config.srvId + "-info-%d{yyyy-MM-dd}.%i.log",
                            log.getLoggerContext()));
            filePolicy.start();
            triggerPolicy.start();
            rfa.setRollingPolicy(filePolicy);
            rfa.start();
            fileAppenders.put(gameBody.config.srvId, rfa);
        }
        log.addAppender(fileAppenders.get(gameBody.config.srvId));
        return log;
    }
}
